import React from 'react';
import RenderEngine from './RenderEngine';
import EventEmitter from '../EventEmitter'

const ACTION_EVENT_KEY = {
  dialog: "action:dialog",
  drawer: "action:drawer",
  url: "action:url",
  ajax: "action:ajax",
  custom: "action:custom"
};

/**
 *
 * <MDDRenderEngine schema={{}}  > </MDDRenderEngine>
 * @params schema
 * @params engine 实例
 * @params modules Map
 * @params onReady(engine)
 */

function MDDRenderEngine(props) {
  const { schema, engine: _engine, modules, onReady } = props;
  console.log('schema==>', schema)
  const [engine] = React.useState(() => createEngine(_engine, modules));
  React.useEffect(() => {
    // 注册动作处理器
    Object.keys(ACTION_EVENT_KEY).forEach((key) => {
      if (ACTION_EVENT_KEY[key]) {
        engine.on(ACTION_EVENT_KEY[key], (schema, notice = []) => {
          const action = engine.getModule(key);
          const [resolve = empty, reject = empty] = notice;
          if (action) {
            const ret = action({ engine, schema });
            if (ret instanceof Promise) {
              ret.then(resolve).catch(reject);
            }
          } else {
            reject(new Error(`action name ${ACTION_EVENT_KEY[key]} not defined in engine`));
          }
        });
      }
    });
    onReady && onReady(engine);
    // 监听 URL 发生变化
    const queryModule = engine.getModule('$QUERY');
    if (queryModule) {
      return queryModule.on('queryChange', ([name, value]) => {
        engine.emit(`$QUERY.${name}`, value);
      });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  return <React.Fragment>{engine.render(props.schema)}</React.Fragment>;
}

function empty() {}
/**
 * 创建新的引擎
 */
function createEngine(engine, modules) {
  if (engine instanceof RenderEngine) {
    return engine;
  }

  engine = new RenderEngine();
  if (modules instanceof Map) {
    modules.forEach((value, key) => {
      engine.setModule(key, value);
    });
  }

  return engine;
}

export function setActions(actions) {
  Object.keys(actions).forEach((key) => {
    RenderEngine.setModule(key, actions[key]);
  });
}

export function setComponents(components) {
  Object.keys(components).forEach((key) => {
    RenderEngine.setComponent(key, components[key]);
  });
}

export class JSONWatch extends EventEmitter {
  constructor(data) {
    super();
    this.data = data || {};
  }
  on(a, b) {
    if (a.indexOf(",") > -1) {
      a.split(",").forEach((i) => {
        super.on(i, b);
      });
    } else {
      super.on(a, b);
    }
  }
  off(a, b) {
    if (a.indexOf(",") > -1) {
      a.split(",").forEach((i) => {
        super.off(i, b);
      });
    } else {
      super.off(a, b);
    }
  }
  get(path) {
    return this.getVariable(path);
  }
  getVariable(path) {
    if (typeof path !== "string") {
      console.warn("Not string:", path);
      return "";
    }
    if (path === "$ALL") {
      return this.data;
    }
    if (path.indexOf(".") > -1) {
      path = path.split(".");
      let ret = this.data;
      for (let i = 0; i < path.length; i++) {
        ret = ret[path[i]];
        if (ret === void 0) {
          return;
        }
      }
      return ret;
    }
    return this.data[path];
  }
  set(path, value) {
    if (path.indexOf(".") > -1) {
      const paths = path.split(".");
      let ret = this.data;
      for (let i = 0; i < paths.length - 1; i++) {
        ret = ret[paths[i]];
      }
      ret[paths[paths.length - 1]] = value;
    } else {
      this.data[path] = value;
    }
    this.emit(path, value);
    if (value && Object.keys(value).length) {
      Object.keys(value).forEach((key) => {
        this.emit(`${path}.${key}`, value[key]);
      });
    }
    this.emit("$updated", [path, value]);
  }
};

export default MDDRenderEngine;
